/*
 * bsp_i2c.c
 *
 *  Created on: 2023年6月28日
 *      Author: mcealt_DS
 */
#include <stdio.h>
#include "bsp_i2c.h"
#include "em_i2c.h"
#include "softwareMultiTimer.h"
#include "app_log.h"
#include "btl_reset_info.h"

#define I2C_ERROR_CN_MAX       3

#define ACK           0            //应答信号
#define NACK        1             //非应答信号
#define I2C_SCL_1()  GPIO_PinOutSet(I2C_SCL_PORT, I2C_SCL_PIN)
#define I2C_SCL_0()  GPIO_PinOutClear(I2C_SCL_PORT, I2C_SCL_PIN)

#define I2C_SDA_1()  GPIO_PinOutSet(I2C_SDA_PORT, I2C_SDA_PIN)
#define I2C_SDA_0()  GPIO_PinOutClear(I2C_SDA_PORT, I2C_SDA_PIN)

#define I2C_SDA_READ()  GPIO_PinInGet(I2C_SDA_PORT, I2C_SDA_PIN)

static void I2CDelay(void)
{
  uint8_t i;
  for(i=0;i<1;i++)
  {

  }
}
static uint8_t I2C_Write(uint8_t Write_Byte)
{
  uint8_t i,re;
  for(i=0;i<8;i++)
  {
      if(Write_Byte&0x80)
      {
          I2C_SDA_1();
      }
      else
      {
          I2C_SDA_0();
      }
      I2CDelay();
      I2C_SCL_1();
      I2CDelay();
      I2C_SCL_0();
      if (i == 7)
      {
          I2C_SDA_1();
      }
      Write_Byte <<= 1;
  }
  I2CDelay();
  I2C_SCL_1();
  I2CDelay();

  if(I2C_SDA_READ() == 1)
  {
      re=NACK;
  }
  else
  {
      re=ACK;
  }

  I2C_SCL_0();
  I2CDelay();
  return re;
}

void I2C_software_reset(void)
{
  DS_app_log_error("I2C bus reset\n");
  //start
  I2C_SDA_1();
  I2C_SCL_1();
  I2CDelay();
  I2C_SDA_0();
  I2CDelay();
  I2C_SCL_0();
  I2CDelay();
  //00
  I2C_Write(0x00);
  //06
  I2C_Write(0x06);
  //stop
  I2C_SDA_0();
  I2C_SCL_1();
  I2CDelay();
  I2C_SDA_1();
  I2CDelay();
}

void I2C_error_mcureboot(void)
{
  BootloaderResetCause_t* resetCause = (BootloaderResetCause_t*) (SRAM_BASE);
  resetCause->reason = BOOTLOADER_RESET_REASON_I2C_ERROR;
  resetCause->signature = BOOTLOADER_RESET_SIGNATURE_VALID;
  NVIC_SystemReset();
}
void I2C_LeaderWrite(uint16_t followerAddress, uint8_t targetAddress, uint8_t *txBuff, uint8_t numBytes)
{
  // Transfer structure
  I2C_TransferSeq_TypeDef i2cTransfer;
  I2C_TransferReturn_TypeDef result;
  uint8_t txBuffer[I2C_TXBUFFER_SIZE + 1];
  uint8_t i2c_error_cn = 0;
  uint32_t ticks = 0;

  if(GPIO_PinInGet(I2C_SDA_PORT, I2C_SDA_PIN) == 0){
      I2C_Reset(I2C0);
      extern void SM_I2C_init (void);
      SM_I2C_init();
      I2C_software_reset();
  }

  txBuffer[0] = targetAddress;
  for(int i = 0; i < numBytes; i++)
  {
      txBuffer[i + 1] = txBuff[i];
  }

  // Initialize I2C transfer
  i2cTransfer.addr          = followerAddress;
  i2cTransfer.flags         = I2C_FLAG_WRITE;
  i2cTransfer.buf[0].data   = txBuffer;
  i2cTransfer.buf[0].len    = numBytes + 1;
  i2cTransfer.buf[1].data   = NULL;
  i2cTransfer.buf[1].len    = 0;

  result = I2C_TransferInit(I2C0, &i2cTransfer);

  // Send data
  ticks = READ_SYS_RTC_COUNT();
  while (result == i2cTransferInProgress) {
      result = I2C_Transfer(I2C0);
      if(READ_SYS_RTC_COUNT() - ticks > 655){
          DS_app_log_error("I2C timeout\n");
          i2c_error_cn++;
          if(i2c_error_cn <= I2C_ERROR_CN_MAX){
              I2C_Reset(I2C0);
              extern void SM_I2C_init (void);
              SM_I2C_init();
              I2C_software_reset();
              result = I2C_TransferInit(I2C0, &i2cTransfer);
              DS_app_log_error("I2C reset,cn=%d\n",i2c_error_cn);
              ticks = READ_SYS_RTC_COUNT();
          }
          else {
              //TODO: mcu reset
              I2C_error_mcureboot();
          }
      }
  }

  if (result != i2cTransferDone) {
      DS_app_log_error("I2C error,ret=%d\n",result);
      I2C_software_reset();
  }
}


/***************************************************************************//**
 * @brief I2C read numBytes from follower device starting at target address
 ******************************************************************************/
void I2C_LeaderRead(uint16_t followerAddress, uint8_t targetAddress, uint8_t *rxBuff, uint8_t numBytes)
{
  // Transfer structure
  I2C_TransferSeq_TypeDef i2cTransfer;
  I2C_TransferReturn_TypeDef result;
  uint8_t i2c_error_cn = 0;
  uint32_t ticks = 0;

  if(GPIO_PinInGet(I2C_SDA_PORT, I2C_SDA_PIN) == 0){
      I2C_Reset(I2C0);
      extern void SM_I2C_init (void);
      SM_I2C_init();
      I2C_software_reset();
  }

  // Initialize I2C transfer
  i2cTransfer.addr          = followerAddress;
  i2cTransfer.flags         = I2C_FLAG_WRITE_READ; // must write target address before reading
  i2cTransfer.buf[0].data   = &targetAddress;
  i2cTransfer.buf[0].len    = 1;
  i2cTransfer.buf[1].data   = rxBuff;
  i2cTransfer.buf[1].len    = numBytes;

  result = I2C_TransferInit(I2C0, &i2cTransfer);

  // Send data
  while (result == i2cTransferInProgress) {
    result = I2C_Transfer(I2C0);
    if(READ_SYS_RTC_COUNT() - ticks > 655){
        DS_app_log_error("I2C timeout\n");
        i2c_error_cn++;
        if(i2c_error_cn <= I2C_ERROR_CN_MAX){
            I2C_Reset(I2C0);
            extern void SM_I2C_init (void);
            SM_I2C_init();
            I2C_software_reset();
            result = I2C_TransferInit(I2C0, &i2cTransfer);
            DS_app_log_error("I2C reset,cn=%d\n",i2c_error_cn);
            ticks = READ_SYS_RTC_COUNT();
        }
        else {
            //TODO: mcu reset
            I2C_error_mcureboot();
        }
    }
  }

  if (result != i2cTransferDone) {
      DS_app_log_error("I2C error,ret=%d\n",result);
      I2C_software_reset();
  }
}
